package cn.christ.com.mobilesafe.common.utils;

import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Binder;
import android.os.Build;
import android.os.Environment;
import android.os.IBinder;
import android.provider.Settings;
import android.support.annotation.Nullable;
import android.support.annotation.RequiresApi;
import android.support.v4.app.NotificationCompat;
import android.support.v4.content.FileProvider;
import android.support.v4.content.LocalBroadcastManager;
import android.text.TextUtils;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.ref.WeakReference;
import java.net.HttpURLConnection;
import java.net.URL;

import cn.christ.com.mobilesafe.R;


/**
 * 类功能描述：</br>
 * 自定义Service后台下载app——跳出DownloadManager系统下载之坑 </br>
 * 修改人：   yuyahao
 *
 * @version 1.0 </p> 修改时间：</br> 修改备注：</br>
 */
public class UpdateService extends Service {
    public static final String TAG = "UpdateService";
    public static String ACTION = "";
    public static final String STATUS = "status";
    public static final String PROGRESS = "progress";
    public static boolean DEBUG = true;

    //下载大小通知频率
    public static final int UPDATE_NUMBER_SIZE = 1;
    public static final int DEFAULT_RES_ID = -1;

    public static final int UPDATE_PROGRESS_STATUS = 0; //更新中的状态
    public static final int UPDATE_ERROR_STATUS = -1; //更新错误的状态
    public static final int UPDATE_SUCCESS_STATUS = 1; //更新成功的状态

    //params
    private static final String URL = "downloadUrl";
    private static final String ICO_RES_ID = "icoResId";
    private static final String ICO_SMALL_RES_ID = "icoSmallResId";
    private static final String UPDATE_PROGRESS = "updateProgress";
    private static final String STORE_DIR = "storeDir"; //sd卡存储的位置
    private static final String DOWNLOAD_NOTIFICATION_FLAG = "downloadNotificationFlag";
    private static final String DOWNLOAD_SUCCESS_NOTIFICATION_FLAG = "downloadSuccessNotificationFlag";
    private static final String DOWNLOAD_ERROR_NOTIFICATION_FLAG = "downloadErrorNotificationFlag";
    private static final String IS_SEND_BROADCAST = "isSendBroadcast";


    private String downloadUrl; //下载的urL
    private int icoResId; //大图标             //default app ico
    private int icoSmallResId; //小的图标
    private int updateProgress;   //更新的进度 update notification progress when it add number
    private static String storeDir;      //存储的文字 字符串default sdcard/Android/package/update
    private int downloadNotificationFlag; //下载通知栏的标记
    private int downloadSuccessNotificationFlag; //下载成功的通知栏标记
    private int downloadErrorNotificationFlag; //下载失败错误的通知栏的标记
    private boolean isSendBroadcast; //发送广播

    private UpdateProgressListener updateProgressListener; //监听器
    private LocalBinder localBinder = new LocalBinder(); //本地绑定
    private NotificationChannel channel;


    //*******************************1.建造者模式初始化*********************************************

    /**
     * a builder class helper use UpdateService
     * 1.建造者模式 静态内部类初始化数据 启动服务
     */
    public static class Builder {

        private String downloadUrl;  //下载的url
        private int icoResId = DEFAULT_RES_ID;   //默认app的图片资源id           //default app ico
        private int icoSmallResId = DEFAULT_RES_ID;  //app的小图资源id
        private int updateProgress = UPDATE_NUMBER_SIZE;   //更新的进度条 update notification progress when it add number
        private String storeDir;          // default sdcard/Android/package/update
        private int downloadNotificationFlag;
        private int downloadSuccessNotificationFlag;
        private int downloadErrorNotificationFlag;
        private boolean isSendBroadcast;


        protected Builder(String downloadUrl) {
            this.downloadUrl = downloadUrl;
        }

        /**
         * 构造方法初始化，需要的url，需要HttpURLConnection
         * HttpURLConnection,通过流来下载
         *
         * @param downloadUrl
         */
        public static Builder create(String downloadUrl) {
            //如果url为空，则报空
            if (downloadUrl == null) {
                throw new NullPointerException("downloadUrl == null");
            }
            return new Builder(downloadUrl);
        }


        public Builder setStoreDir(String storeDir) {
            this.storeDir = storeDir;
            return this;
        }


        public Builder setDownloadSuccessNotificationFlag(int downloadSuccessNotificationFlag) {
            this.downloadSuccessNotificationFlag = downloadSuccessNotificationFlag;
            return this;
        }


        public Builder setDownloadErrorNotificationFlag(int downloadErrorNotificationFlag) {
            this.downloadErrorNotificationFlag = downloadErrorNotificationFlag;
            return this;
        }


        /**
         * 自构方法，还是返回这个对象，也是初始化用的
         * 传递进来的是activity的this,加载到栈内存
         *
         * @param context
         * @return
         */
        public Builder build(Context context) {
            if (context == null) {
                throw new NullPointerException("context == null");
            }

            ACTION = context.getPackageName();

            //启动服务，创建意图
            Intent intent = new Intent();
            intent.setClass(context, UpdateService.class); //设置跳转的服务
            intent.putExtra(URL, downloadUrl);//传递url和数据

            //获取图标大图
            if (icoResId == DEFAULT_RES_ID) {
                icoResId = getIcon(context);
            }
            //小图
            if (icoSmallResId == DEFAULT_RES_ID) {
                icoSmallResId = icoResId;
            }
            //传递数据到服务中
            intent.putExtra(ICO_RES_ID, icoResId); //大图
            intent.putExtra(STORE_DIR, storeDir); //
            intent.putExtra(ICO_SMALL_RES_ID, icoSmallResId); //小图
            intent.putExtra(UPDATE_PROGRESS, updateProgress); //更新的进度条
            intent.putExtra(DOWNLOAD_NOTIFICATION_FLAG, downloadNotificationFlag); //下载进度条通知栏标记
            intent.putExtra(DOWNLOAD_SUCCESS_NOTIFICATION_FLAG, downloadSuccessNotificationFlag);  //下载成功标记
            intent.putExtra(DOWNLOAD_ERROR_NOTIFICATION_FLAG, downloadErrorNotificationFlag); //下载失败的标记
            intent.putExtra(IS_SEND_BROADCAST, isSendBroadcast); //发送的广播
            context.startService(intent); //启动服务
            return this; //返回对象
        }

        /**
         * 返回app的图标资源
         *
         * @param context
         * @return
         */
        private int getIcon(Context context) {
            //获取包管理器
            final PackageManager packageManager = context.getPackageManager();
            ApplicationInfo appInfo = null;
            try {
                //通过包管理器，获取到application节点的信息
                appInfo = packageManager.getApplicationInfo(context.getPackageName(), PackageManager.GET_META_DATA);
            } catch (PackageManager.NameNotFoundException e) {
                e.printStackTrace();
            }
            if (appInfo != null) {
                return appInfo.icon;
            }
            return 0;
        }
    }


    private boolean startDownload;//开始下载
    //private int lastProgressNumber; //最后进程的大小
    private NotificationCompat.Builder builder;  //通知栏创建
    private NotificationManager manager; //通知栏管理器
    private int notifyId; //通知的id
    private String appName; //app的名字
    private LocalBroadcastManager localBroadcastManager; //本地广播管理器
    private Intent localIntent; //意图
    private DownloadApk downloadApkTask; //下载的apk类，线程下载

    //*******************************2.服务操作****************************************************

    /**
     * 2创建服务
     */
    @Override
    public void onCreate() {
        super.onCreate();
        appName = getApplicationName();
    }

    /**
     * 2.1绑定本地localBinder
     *
     * @param intent
     * @return
     */
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return localBinder;
    }

    /**
     * 2.3服务和监听器绑定在一起 Class used for the client Binder.
     * 创建本地binder
     */
    public class LocalBinder extends Binder {
        /**
         * set update progress call back
         * 设置监听器到服务中
         *
         * @param listener
         */
        public void setUpdateProgressListener(UpdateProgressListener listener) {
            UpdateService.this.setUpdateProgressListener(listener);
        }
    }

    /**
     * 2.4开始服务
     *
     * @param intent
     * @param flags
     * @param startId
     * @return
     */
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        if (!startDownload && intent != null) { //初始化操作
            startDownload = true;
            downloadUrl = intent.getStringExtra(URL);
            icoResId = intent.getIntExtra(ICO_RES_ID, DEFAULT_RES_ID);
            icoSmallResId = intent.getIntExtra(ICO_SMALL_RES_ID, DEFAULT_RES_ID);
            storeDir = intent.getStringExtra(STORE_DIR); //sk卡存储的位置
            updateProgress = intent.getIntExtra(UPDATE_PROGRESS, UPDATE_NUMBER_SIZE);
            downloadNotificationFlag = intent.getIntExtra(DOWNLOAD_NOTIFICATION_FLAG, 0);
            downloadErrorNotificationFlag = intent.getIntExtra(DOWNLOAD_ERROR_NOTIFICATION_FLAG, 0);
            downloadSuccessNotificationFlag = intent.getIntExtra(DOWNLOAD_SUCCESS_NOTIFICATION_FLAG, 0);
            isSendBroadcast = intent.getBooleanExtra(IS_SEND_BROADCAST, false);


            if (DEBUG) {
                LogUtils.e(TAG, "downloadUrl: " + downloadUrl);
                LogUtils.e(TAG, "icoResId: " + icoResId);
                LogUtils.e(TAG, "icoSmallResId: " + icoSmallResId);
                LogUtils.e(TAG, "storeDir: " + storeDir);
                LogUtils.e(TAG, "updateProgress: " + updateProgress);
                LogUtils.e(TAG, "downloadNotificationFlag: " + downloadNotificationFlag);
                LogUtils.e(TAG, "downloadErrorNotificationFlag: " + downloadErrorNotificationFlag);
                LogUtils.e(TAG, "downloadSuccessNotificationFlag: " + downloadSuccessNotificationFlag);
                LogUtils.e(TAG, "isSendBroadcast: " + isSendBroadcast);
            }

            notifyId = startId;
            buildNotification(); //通知栏初始化
            buildBroadcast(); //本地广播初始化
            downloadApkTask = new DownloadApk(this); //下载线程初始化
            downloadApkTask.execute(downloadUrl); //开始下载
        }
        return super.onStartCommand(intent, flags, startId);
    }


    /**
     * 2.5解绑
     *
     * @param intent
     * @return
     */
    @Override
    public boolean onUnbind(Intent intent) {
        return true;
    }

    /**
     * 2.6服务销毁
     */
    @Override
    public void onDestroy() {
        //线程取消
        if (downloadApkTask != null) {
            downloadApkTask.cancel(true);
        }

        //监听器设置为空
        if (updateProgressListener != null) {
            updateProgressListener = null;
        }
        //本地广播的意图设置为空
        localIntent = null;
        //构造设置为null
        builder = null;
        super.onDestroy();
    }

    //*******************************3.线程下载操作***********************************************

    /**
     * 3.apk下载的线程asyncTask,三个构造参数，4个步骤
     * 异步任务，通过此类,可以实现UI线程和后台线程进行通讯,后台线程执行异步任务,并把结果返回给UI线程.
     * 是一个抽象类
     * Params:启动任务时输入的参数类型. url
     * Progress:后台任务执行中返回进度值的类型 进度条.
     * Result:后台任务执行完成后返回结果的类型. 完成后的结果标记
     */
    private static class DownloadApk extends AsyncTask<String, Integer, String> {

        //弱引用(WeakReference)
        private WeakReference<UpdateService> updateServiceWeakReference;

        //构造方法初始化，服务
        public DownloadApk(UpdateService service) {
            updateServiceWeakReference = new WeakReference<>(service);
        }

        /**
         * onPreExecute:执行后台耗时操作前被调用,通常用于进行初始化操作.
         */
        @Override
        protected void onPreExecute() {
            super.onPreExecute();
            //开始服务
            UpdateService service = updateServiceWeakReference.get();
            if (service != null) {
                service.start();
            }
        }

        /**
         * 必须重写,异步执行后台线程要完成的任务,耗时操作将在此方法中完成.
         * 返回保存apk绝对路径
         *
         * @param params
         * @return
         */
        @Override
        protected String doInBackground(String... params) {
            //删除方法  删除某个文件夹下的文件，及其文件 获取到绝对路径
            DataCleanManager.deleteFilesByDirectory2(
                    String.valueOf(UpdateService.getDownloadDir(updateServiceWeakReference.get())
                            .getAbsolutePath()));
            final String downloadUrl = params[0];

            //创建文件，保存文件的名字
            final File file = new File(UpdateService.getDownloadDir(updateServiceWeakReference.get()),
                    UpdateService.getSaveFileName(downloadUrl));
//            if (DEBUG) {
//                LogUtils.e(TAG, "download url is " + downloadUrl);
//                LogUtils.e(TAG, "download apk cache at " + file.getAbsolutePath());
//            }
            File dir = file.getParentFile();
            if (!dir.exists()) {
                dir.mkdirs();
            }

            //网络下载
            HttpURLConnection httpConnection = null;
            InputStream is = null; //字节输入流
            FileOutputStream fos = null; //字节输出流
            int updateTotalSize = 0; //字节总数
            URL url;
            try {
                url = new URL(downloadUrl); //创建url
                httpConnection = (HttpURLConnection) url.openConnection(); //获取到里流
                httpConnection.setConnectTimeout(5000);
                httpConnection.setReadTimeout(5000);

//                if (DEBUG) {
//                    LogUtils.e(TAG, "download status code: " + httpConnection.getResponseCode());
//                }

                if (httpConnection.getResponseCode() != 200) {
                    return null;
                }

                //获取到流的中总字节总数
                updateTotalSize = httpConnection.getContentLength();

                if (file.exists()) {
                    if (updateTotalSize == file.length()) {
                        // 下载完成
                        return file.getAbsolutePath();
                    } else {
                        file.delete();
                    }
                }
                //生成新的文件
                file.createNewFile();
                is = httpConnection.getInputStream();
                fos = new FileOutputStream(file, false);
                byte buffer[] = new byte[4096];

                int readSize = 0;
                int currentSize = 0;
                int progress = 0;

                while ((readSize = is.read(buffer)) > 0) {
                    fos.write(buffer, 0, readSize);
                    currentSize += readSize;
                    int value = (currentSize * 100 / updateTotalSize);
                    if (value != progress) {
                        progress = value;
                        publishProgress(progress);
                    }
                }
                // download success
            } catch (Exception e) {
                e.printStackTrace();
                return null;
            } finally {
                if (httpConnection != null) {
                    httpConnection.disconnect();
                }
                if (is != null) {
                    try {
                        is.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                if (fos != null) {
                    try {
                        fos.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
            return file.getAbsolutePath();
        }

        /**
         * 当在doInBackground方法中调用publishProgress方法更新任务执行进度后,
         * 将调用此方法.通过此方法我们可以知晓任务的完成进度.
         *
         * @param values
         */
        @Override
        protected void onProgressUpdate(Integer... values) {
            super.onProgressUpdate(values);
            if (DEBUG) {
                LogUtils.e(TAG, "current progress is " + values[0]);
            }
            UpdateService service = updateServiceWeakReference.get();
            if (service != null) {
                service.update(values[0]);
            }
        }

        /**
         * 当doInBackground方法完成后,系统将自动调用此方法,
         * 并将doInBackground方法返回的值传入此方法.通过此方法进行UI的更新.
         *
         * @param s
         */
        @Override
        protected void onPostExecute(String s) {
            super.onPostExecute(s);
            UpdateService service = updateServiceWeakReference.get();
            if (service != null) {
                service.update(100);
                if (s != null) {
                    service.success(s);
                } else {
                    service.error();
                }
            }
        }
    }

    //*******************************4.监听器回调*************************************************

    /**
     * 4.1开始下载操作
     */
    private void start() {
        builder.setContentTitle(appName);
        //修改Text
        //原来的是这样的getString(R.string.update_app_model_prepare, 1)
        builder.setContentText(getString(R.string.update_app_model_prepare));
        manager.notify(notifyId, builder.build()); //通知通知栏
        sendLocalBroadcast(UPDATE_PROGRESS_STATUS, 1); //发送本地广播下载
        if (updateProgressListener != null) {
            updateProgressListener.start();
        }
    }

    /**
     * 4.2更新进度条数据
     *
     * @param progress download percent , max 100
     */
    private void update(int progress) {
        if (progress >= updateProgress) {
            //lastProgressNumber = progress;
            LogUtils.d(progress + "---");
            builder.setProgress(100, progress, false);
            //设置正在下载的进度条数
            builder.setContentText(getString(R.string.update_app_model_progress, progress, "%"));
            //通知栏管理器，通知
            manager.notify(notifyId, builder.build());
            //发送本地广播，进度条
            sendLocalBroadcast(UPDATE_PROGRESS_STATUS, progress);
            if (updateProgressListener != null) {
                updateProgressListener.update(progress);
            }
        }
    }

    /**
     * 4.3下载成功的回调
     *
     * @param path
     */

    private void success(String path) {
        builder.setProgress(0, 0, false);
        builder.setContentText(getString(R.string.update_app_model_success));  //设置内容

        manager.cancel(0); //通知栏管理器取消
        if (FileHelper.checkFileIsExists(path)) { //文件助手，检查文件是否存在
            LogUtils.d("下载成功");
            Intent i = installIntent(path); //返回意图
            PendingIntent intent = PendingIntent.getActivity(this, 0, i,
                    PendingIntent.FLAG_UPDATE_CURRENT); //使用pendingIntent来装intent
            builder.setContentIntent(intent) //自构造者
                    .setAutoCancel(true)//用户点击就自动消失
                    .setDefaults(downloadSuccessNotificationFlag); //设置下载成功的标记
            Notification n = builder.build(); //通知栏
            n.contentIntent = intent;
            manager.notify(notifyId, n); //通知通知栏
            sendLocalBroadcast(UPDATE_ERROR_STATUS, 1); //发送本地广播
            if (updateProgressListener != null) { //回调下载成功
                updateProgressListener.success();
            }
            startActivity(i); //开始意图
            //IntentFilter filter = new IntentFilter();
        } else {
            DataCleanManager.deleteFilesByDirectory2(storeDir);
        }
        stopSelf(); //停止服务
    }

    /**
     * 4.4失败的下载操作
     */
    private void error() {
        //发送加载web的广播
        builder.setProgress(0, 0, false);
        Intent i = webLauncher(downloadUrl);
        //PendingIntent这个类用于处理即将发生的事情。比如在通知Notification中用于跳转页面，但不是马上跳转。
        PendingIntent intent = PendingIntent.getActivity(this, 0, i,
                PendingIntent.FLAG_UPDATE_CURRENT);
        builder.setContentText(getString(R.string.update_app_model_error));
        builder.setContentIntent(intent);
        builder.setProgress(0, 0, false);
        builder.setDefaults(downloadErrorNotificationFlag);
        Notification n = builder.build();
        n.contentIntent = intent;
        manager.notify(notifyId, n); //通知栏管理器，通知
        sendLocalBroadcast(UPDATE_ERROR_STATUS, -1); //发送本地广播
        if (updateProgressListener != null) {
            updateProgressListener.error();
        }
        stopSelf();
    }


    //*******************************5.功能类******************************************************

    /**
     * 工具类 设置启动web的intent
     *
     * @param downloadUrl
     * @return
     */
    private static Intent webLauncher(String downloadUrl) {
        Uri download = Uri.parse(downloadUrl); //字符串解析成uri
        Intent intent = new Intent(Intent.ACTION_VIEW, download);
        //通过广播来启动Activity的时候如果不设置intent的FLAG_ACTIVITY_NEW_TASK属性，就会报这个异常
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        return intent;
    }

    /**
     * 工具类 返回下载路径的名字
     *
     * @param downloadUrl
     * @return
     */
    private static String getSaveFileName(String downloadUrl) {
        //没有名字的apk
        if (downloadUrl == null || TextUtils.isEmpty(downloadUrl)) {
            return "noName.apk";
        }
        //返回下载路径的名字
        return downloadUrl.substring(downloadUrl.lastIndexOf("/"));
    }

    /**
     * 工具类 获取下载的文件
     *
     * @param service
     * @return
     */
    private static File getDownloadDir(UpdateService service) {
        File downloadDir = null;
        //如果SD卡正常挂载
        if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
            //非空判断
            if (service.storeDir != null) {
                //创建sd文件
                downloadDir = new File(Environment.getExternalStorageDirectory(), service.storeDir);
            } else {
                downloadDir = new File(service.getExternalCacheDir(), "update");
            }
        } else {//如果sd卡卸载了，获取到缓存目录，
            downloadDir = new File(service.getCacheDir(), "update");
        }
        //如果文件不存在，创建出来
        if (!downloadDir.exists()) {
            downloadDir.mkdirs();
        }
        return downloadDir;
    }

    /**
     * 方法 本地广播获取实例
     */
    private void buildBroadcast() {
        if (!isSendBroadcast) {
            return;
        }
        //本地广播获取实例
        localBroadcastManager = LocalBroadcastManager.getInstance(this);
        localIntent = new Intent(ACTION);
    }

    /**
     * 方法 发送本地广播
     *
     * @param status
     * @param progress
     */
    private void sendLocalBroadcast(int status, int progress) {
        if (!isSendBroadcast || localIntent == null) {
            return;
        }
        localIntent.putExtra(STATUS, status);
        localIntent.putExtra(PROGRESS, progress);
        localBroadcastManager.sendBroadcast(localIntent);
    }

    /**
     * 方法 构建通知栏
     */
    private void buildNotification() {
        //获取到通知栏管理器
        manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
        //通知栏8.0适配
        //ChannelId为"1",ChannelName为"Channel1"
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            channel = new NotificationChannel("1",
                    "Channel1", NotificationManager.IMPORTANCE_DEFAULT);
            channel.enableLights(true); //是否在桌面icon右上角展示小红点
            channel.setLightColor(Color.GREEN); //小红点颜色
            channel.setShowBadge(true); //是否在久按桌面图标时显示此渠道的通知
            manager.createNotificationChannel(channel);
        }


        builder = new NotificationCompat.Builder(this, "1");
        //修改标题
        //原来的getString(R.string.update_app_model_prepare, appName)
        builder.setContentTitle(getString(R.string.update_app_model_prepare))
                .setWhen(System.currentTimeMillis())// 通知产生的时间，会在通知信息里显示
                .setProgress(100, 1, false)
                .setSmallIcon(icoSmallResId) //设置小图标
                .setLargeIcon(BitmapFactory.decodeResource(
                        getResources(), icoResId)) //设置大图标，BitmapFactory.decodeResource
                .setDefaults(downloadNotificationFlag);
        //通知栏管理器通知
        manager.notify(notifyId, builder.build());


    }

    /**
     * 方法 获取到包名
     *
     * @return
     */
    public String getApplicationName() {
        PackageManager packageManager = null;
        ApplicationInfo applicationInfo = null;
        try {
            packageManager = getApplicationContext().getPackageManager();
            applicationInfo = packageManager.getApplicationInfo(getPackageName(), 0);
        } catch (PackageManager.NameNotFoundException e) {
            applicationInfo = null;
        }
        String applicationName =
                (String) packageManager.getApplicationLabel(applicationInfo);
        return applicationName;
    }

    /**
     * 方法 设置监听器
     *
     * @param updateProgressListener
     */
    public void setUpdateProgressListener(UpdateProgressListener updateProgressListener) {
        this.updateProgressListener = updateProgressListener;
    }


    /**
     * 方法 设置点击通知栏去进行安装的intent
     *
     * @param path
     * @return
     */
    private Intent installIntent(String path) {
        //适配7.0
        Intent installIntent = new Intent(Intent.ACTION_VIEW); //创建intent准备跳转
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
            Uri uri = Uri.fromFile(new File(path)); //路径变成uri
            //通过广播来启动Activity的时候如果不设置intent的FLAG_ACTIVITY_NEW_TASK属性，就会报这个异常
            installIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            installIntent.setDataAndType(uri, "application/vnd.android.package-archive");
        } else {//Android7.0之后获取uri要用contentProvider
            //在AndroidManifest中的android:authorities值
            Uri uri = FileProvider.getUriForFile(getApplicationContext(),
                    getPackageName() + ".fileProvider", new File(path));

            installIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            //添加这一句表示对目标应用临时授权该Uri所代表的文件
            installIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
            installIntent.setDataAndType(uri, "application/vnd.android.package-archive");

            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                //先获取是否有安装未知来源应用的权限
                boolean haveInstallPermission = getApplicationContext().getPackageManager().canRequestPackageInstalls();
                if (!haveInstallPermission) {//没有权限
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                        startInstallPermissionSettingActivity();
                    }
                }
            }
        }

        return installIntent;
    }

    /**
     * 方法 跳转到设置未知权限 适配8.0
     */
    @RequiresApi(api = Build.VERSION_CODES.O)
    private void startInstallPermissionSettingActivity() {
        Uri packageURI = Uri.parse("package:" + getPackageName());
        //注意这个是8.0新API
        Intent intent = new Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES, packageURI);
        startActivity(intent);
    }


    //*******************************6.监听器******************************************************

    public interface UpdateProgressListener {
        /**
         * download start
         * 下载开始
         */
        void start();

        /**
         * update download progress
         * 下载更新
         *
         * @param progress
         */
        void update(int progress);

        /**
         * 下载成功
         * download success
         */
        void success();

        /**
         * 下载错误
         * download error
         */
        void error();
    }

}
